﻿using Abp.Application.Services.Dto;
using Abp.Domain.Repositories;
using Abp.EntityFrameworkCore.Repositories;
using Abp.Extensions;
using Abp.Linq.Extensions;
using Abp.Runtime.Caching;
using Abp.UI;
using ARchGL.Platform.Authorization.Users;
using ARchGL.Platform.Electrocar.Application.Dto;
using ARchGL.Platform.Electrocar.Core;
using ARchGL.Platform.Utils;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace ARchGL.Platform.Electrocar.Application
{
    /// <summary>
    /// 总成，结构和零件属性 实现
    /// </summary>
    public class PropertysAppService : BaseService, ICarModelAppService
    {
        private readonly IRepository<ModelAssemblys, Guid> modelAssemblysRepository;
        private readonly IRepository<ModelDirectorys, Guid> modelDirectorysRepository;
        private readonly IRepository<ModelPropertys, Guid> modelPropertysRepository;

        private readonly UserManager userManager;
        private readonly ICacheManager cacheManager;

        public PropertysAppService(
            IRepository<ModelAssemblys, Guid> _modelAssemblysRepository,
            IRepository<ModelDirectorys, Guid> _modelDirectorysRepository, IRepository<ModelPropertys, Guid> _modelPropertysRepository,
            Services.CarModelsAppService _carModelService1,
            UserManager _userManager, ICacheManager _cacheManager)
        {
            modelAssemblysRepository = _modelAssemblysRepository;
            modelDirectorysRepository = _modelDirectorysRepository;
            modelPropertysRepository = _modelPropertysRepository;
            userManager = _userManager;
            cacheManager = _cacheManager;
        }

        #region 总成属性

        /// <summary>
        /// 创建总成属性
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<Guid> CreateModelAssembly(ModelAssemblysDto input)
        {
            var entity = ObjectMapper.Map<ModelAssemblys>(input);
            await modelAssemblysRepository.InsertAsync(entity);
            return entity.Id;
        }

        /// <summary>
        /// 删除总成属性
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task RemoveModelAssembly(EntityDto<Guid> input)
        {
            var entity = await modelAssemblysRepository.GetAsync(input.Id);
            if (entity == null) throw new UserFriendlyException("属性不存在，请重新输入");

            var count = modelAssemblysRepository.GetAll().Count(x => x.ParentId == entity.Id);
            if (count > 0) throw new UserFriendlyException($"该属性下有{count}条信息，不能删除");

            await modelAssemblysRepository.DeleteAsync(entity);
        }

        /// <summary>
        /// 编辑总成属性
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task ModifyModelAssembly(ModelAssemblysDto input)
        {
            var entity = await modelAssemblysRepository.GetAsync(input.Id);
            if (entity == null) throw new UserFriendlyException("属性不存在，请重新输入");
            entity.Name = input.Name;
            //entity.Type = input.Type;
            await modelAssemblysRepository.UpdateAsync(entity);
        }

        /// <summary>
        /// 调整总成属性排序位置
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task ModifyModelAssemblySort(SortInput input)
        {
            var entity = await modelAssemblysRepository.GetAsync(input.Id);
            if (entity == null) throw new UserFriendlyException("属性不存在，请重新输入");
            var sql = $"UPDATE {GetTableName<ModelAssemblys>()} SET Sort = @Sort WHERE Id = @Id";
            var dbContext = modelAssemblysRepository.GetDbContext().Database;

            var currentList = modelAssemblysRepository.GetAll().Where(x => x.ProjectId == entity.ProjectId && x.ParentId == entity.ParentId).ToList();

            var type = input.Sort > entity.Sort ? +1 : -1;//获取升降标识
            int periods = type > 0 ? entity.Sort : input.Sort;//起数
            var end = type > 0 ? input.Sort : entity.Sort;//止数

            if (currentList.Any())//更新同级目录下排序位置
            {
                var sortList = currentList.Where(x => x.Sort >= periods && x.Sort <= end).OrderBy(x => x.Sort);
                foreach (var item in sortList)
                {
                    item.Sort = type > 0 ? --item.Sort : ++item.Sort;
                    if (item.Sort > currentList.Count) item.Sort = currentList.Count;//上边界
                    if (item.Sort <= 0) item.Sort = 1;//下边界
                    dbContext.ExecuteSqlCommand(sql, item.Sort, item.Id);
                }
            }
            dbContext.ExecuteSqlCommand(sql, input.Sort, entity.Id);
        }

        /// <summary>
        /// 获取总成属性-分页数据集合
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<PagedResultDto<ModelAssemblysDto>> QueryModelAssemblysPagedList(ModelAssemblysInput input)
        {
            try
            {
                var query = modelAssemblysRepository.GetAll()
                       .Where(x => x.ProjectId == input.ProjectId)
                       .WhereIf(!input.Keywords.IsNullOrWhiteSpace(), x => x.Name.Contains(input.Keywords))
                       .WhereIf(input.ParentIdList.Any(), x => input.ParentIdList.Contains(x.ParentId));

                var result = await query.OrderBy(x => x.Sort).PageByAsync(input);
                return new PagedResultDto<ModelAssemblysDto>(query.Count(),
                    ObjectMapper.Map<List<ModelAssemblysDto>>(result.ToList()));
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        #endregion

        #region 结构属性

        /// <summary>
        /// 创建结构属性
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<Guid> CreateModelDirectory(ModelDirectorysDto input)
        {
            var entity = ObjectMapper.Map<ModelDirectorys>(input);
            //entity.CreatorUserName = userManager.UserName;
            
            await modelDirectorysRepository.InsertAsync(entity);

            //设置总成默认属性
            if (ModelDirectoryType.总成 == entity.Type)
            {
                var id = Guid.NewGuid().ToString().Substring(0, 31);//Guid 后面5位0在方法中累加
                string.Intern(id);
                var assemblyPropertysList = await new Init().SetAssemblyPropertys(id, entity.ProjectId, entity.Id);
                foreach(var item in assemblyPropertysList)
                {
                    await modelAssemblysRepository.InsertAsync(item);
                }

            }
            //设置零件默认属性
            else
            {
                var id = Guid.NewGuid().ToString().Substring(0, 31);//Guid 后面5位0在方法中累加
                string.Intern(id);
                var propertysList = await new Init().SetModelPropertys(id, entity.Id);
                foreach(var item in propertysList)
                {
                    item.ProjectId = entity.ProjectId;
                    await modelPropertysRepository.InsertAsync(item);
                }
            }
            return entity.Id;
        }

        /// <summary>
        /// 删除结构属性
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task RemoveModelDirectory(EntityDto<Guid> input)
        {
            var entity = await modelDirectorysRepository.GetAsync(input.Id);
            if (entity == null) throw new UserFriendlyException("属性不存在，请重新输入");

            var count = modelDirectorysRepository.GetAll().Count(x => x.ParentId == entity.Id);
            if (count > 0) throw new UserFriendlyException($"该属性下有{count}条信息，不能删除");

            await modelDirectorysRepository.DeleteAsync(entity);
        }

        /// <summary>
        /// 编辑结构属性
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task ModifyModelDirectory(ModelDirectorysDto input)
        {
            var entity = await modelDirectorysRepository.GetAsync(input.Id);
            if (entity == null) throw new UserFriendlyException("属性不存在，请重新输入");
            entity.Name = input.Name;
            entity.Type = input.Type;
            await modelDirectorysRepository.UpdateAsync(entity);
        }

        /// <summary>
        /// 调整结构属性排序位置
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task ModifyModelDirectorySort(SortInput input)
        {
            var entity = await modelDirectorysRepository.GetAsync(input.Id);
            if (entity == null) throw new UserFriendlyException("属性不存在，请重新输入");
            var sql = $"UPDATE {GetTableName<ModelDirectorys>()} SET Sort = @Sort WHERE Id = @Id";
            var dbContext = modelAssemblysRepository.GetDbContext().Database;

            var currentList = modelDirectorysRepository.GetAll().Where(x => x.ParentId == entity.ParentId && x.ParentId == entity.ParentId).ToList();

            var type = input.Sort > entity.Sort ? +1 : -1;//获取升降标识
            int periods = type > 0 ? entity.Sort : input.Sort;//起数
            var end = type > 0 ? input.Sort : entity.Sort;//止数

            if (currentList.Any())//更新同级目录下排序位置
            {
                var sortList = currentList.Where(x => x.Sort >= periods && x.Sort <= end).OrderBy(x => x.Sort);
                foreach (var item in sortList)
                {
                    item.Sort = type > 0 ? --item.Sort : ++item.Sort;
                    if (item.Sort > currentList.Count) item.Sort = currentList.Count;//上边界
                    if (item.Sort <= 0) item.Sort = 1;//下边界
                    dbContext.ExecuteSqlCommand(sql, item.Sort, item.Id);
                }
            }
            dbContext.ExecuteSqlCommand(sql, input.Sort, entity.Id);
        }

        /// <summary>
        /// 获取结构属性-分页数据集合
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<PagedResultDto<ModelDirectorysDto>> QueryModelDirectorysPagedList(ModelDirectorysInput input)
        {
            try
            {
                //return await cacheManager.GetCache("QueryModelDirectorysPagedList").Get("asdf", async cache =>
                // {
                var query = modelDirectorysRepository.GetAll()
                       .Where(x => x.ProjectId == input.ProjectId)
                       .WhereIf(!input.Keywords.IsNullOrWhiteSpace(), x => x.Name.Contains(input.Keywords) || x.ModelId.Contains(input.Keywords))
                       .WhereIf(input.ParentIdList.Any(), x => input.ParentIdList.Contains(x.ParentId));

                var result = await query.OrderBy(x => x.Sort).PageByAsync(input);
                return new PagedResultDto<ModelDirectorysDto>(query.Count(),
                    ObjectMapper.Map<List<ModelDirectorysDto>>(result.ToList()));
                //});
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public async Task<PagedResultDto<ModelDirectorysDto>> QueryModelDirectorysPagedList1(ModelDirectorysInput input)
        {
            try
            {
                var query = modelDirectorysRepository.GetAll()
                        .Where(x => x.ProjectId == input.ProjectId)
                        .WhereIf(!input.Keywords.IsNullOrWhiteSpace(), x => x.Name.Contains(input.Keywords) || x.ModelId.Contains(input.Keywords))
                        .WhereIf(input.ParentIdList.Any(), x => input.ParentIdList.Contains(x.ParentId))
                        .Select(x => new ModelDirectorysDto { Id = x.Id, Name = x.Name, Sort = x.Sort, Level = x.Level });

                var result = await query.OrderBy(x => x.Sort).PageByAsync(input);
                return new PagedResultDto<ModelDirectorysDto>(query.Count(),
                    ObjectMapper.Map<List<ModelDirectorysDto>>(result.ToList()));
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        #endregion

        #region 零件属性

        /// <summary>
        /// 创建零件属性
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<Guid> CreateModelProperty(ModelPropertysDto input)
        {
            var entity = ObjectMapper.Map<ModelPropertys>(input);
            entity.CreatorUserName = userManager.UserName;
            await modelPropertysRepository.InsertAsync(entity);
            return entity.Id;
        }

        /// <summary>
        /// 删除零件属性
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task RemoveModelProperty(EntityDto<Guid> input)
        {
            var entity = await modelPropertysRepository.GetAsync(input.Id);
            if (entity == null) throw new UserFriendlyException("属性不存在，请重新输入");

            var count = modelPropertysRepository.GetAll().Count(x => x.ParentId == entity.Id);
            if (count > 0) throw new UserFriendlyException($"该属性下有{count}条信息，不能删除");

            await modelPropertysRepository.DeleteAsync(entity);
        }

        /// <summary>
        /// 编辑零件属性
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task ModifyModelProperty(ModelPropertysDto input)
        {
            var entity = await modelPropertysRepository.GetAsync(input.Id);
            if (entity == null) throw new UserFriendlyException("属性不存在，请重新输入");
            //entity = ObjectMapper.Map<ModelPropertys>(input);
            entity.Name = input.Name;
            entity.Type = input.Type;
            entity.Value = input.Value;

            var sadf = entity.Type == 1
                ? Newtonsoft.Json.JsonConvert.DeserializeObject<ValueStruct>(input.Value)
                : Newtonsoft.Json.JsonConvert.DeserializeObject<ValueAndFileStruct>(input.Value);

            await modelPropertysRepository.UpdateAsync(entity);
        }

        /// <summary>
        /// 调整零件属性排序位置
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task ModifyModelPropertySort(SortInput input)
        {
            var entity = await modelPropertysRepository.GetAsync(input.Id);
            if (entity == null) throw new UserFriendlyException("属性不存在，请重新输入");
            var sql = $"UPDATE {GetTableName<ModelPropertys>()} SET Sort = @Sort WHERE Id = @Id";
            var dbContext = modelPropertysRepository.GetDbContext().Database;

            var currentList = modelPropertysRepository.GetAll()
                .WhereIf(input.DirectoryId != Guid.Empty, x => x.DirectoryId == input.DirectoryId)
                .Where(x => x.ProjectId == entity.ProjectId && x.ParentId == entity.ParentId).ToList();

            var type = input.Sort > entity.Sort ? +1 : -1;//获取升降标识
            int periods = type > 0 ? entity.Sort : input.Sort;//起数
            var end = type > 0 ? input.Sort : entity.Sort;//止数

            if (currentList.Any())//更新同级目录下排序位置
            {
                var sortList = currentList.Where(x => x.Sort >= periods && x.Sort <= end).OrderBy(x => x.Sort);
                foreach (var item in sortList)
                {
                    item.Sort = type > 0 ? --item.Sort : ++item.Sort;
                    if (item.Sort > currentList.Count) item.Sort = currentList.Count;//上边界
                    if (item.Sort <= 0) item.Sort = 1;//下边界
                    dbContext.ExecuteSqlCommand(sql, item.Sort, item.Id);
                }
            }
            dbContext.ExecuteSqlCommand(sql, input.Sort, entity.Id);
        }

        /// <summary>
        /// 获取零件属性-分页数据集合
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<PagedResultDto<ModelPropertysDto>> QueryModelPropertysPagedList(ModelPropertysInput input)
        {
            try
            {
                var query = modelPropertysRepository.GetAll()
                    .Where(x => x.ProjectId == input.ProjectId)
                    .WhereIf(input.ParentIdList.Any(), x => input.ParentIdList.Contains(x.ParentId))
                    .WhereIf(input.DirectoryIdList.Any(), x => input.DirectoryIdList.Contains(x.DirectoryId));

                var result = await query.OrderBy(x => x.Sort).PageByAsync(input);
                return new PagedResultDto<ModelPropertysDto>(query.Count(),
                    ObjectMapper.Map<List<ModelPropertysDto>>(result.ToList()));
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        #endregion

        #region 绑定解绑

        /// <summary>
        /// 绑定零件
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task BindComponent(BindComponentInput input)
        {
            var entity = await modelDirectorysRepository.FirstOrDefaultAsync(x => x.Id == input.DirectoryId);
            if (entity == null) throw new UserFriendlyException("结构不存在，请重新选择");

            if (entity.Type != ModelDirectoryType.零件)
                throw new UserFriendlyException("只能绑定零件，请重新选择");

            //关联零件与模型组件
            var modelIdList = new List<string>();
            if (!string.IsNullOrWhiteSpace(entity.ModelId))
            {
                var currentModelIdList = JArray.Parse(entity.ModelId);//现有零件
                var list = new List<string>();
                foreach (var item in currentModelIdList)
                {
                    list.Add(item.Value<string>());
                }
                modelIdList.AddRange(list);
            }

            var inputList = input.ModelIdList.Distinct().ToList();
            if (inputList.Count == 0) return;
            modelIdList.AddRange(inputList);//传入零件

            var modelIds = JsonConvert.SerializeObject(modelIdList);
            if (modelIds == null) modelIds = string.Empty;

            entity.ModelId = modelIds;
            entity.Count = modelIdList.Count;
            await modelDirectorysRepository.UpdateAsync(entity);

            //更新已绑定零件总数
            var parentDirectorys = await modelDirectorysRepository.FirstOrDefaultAsync(entity.ParentId);
            parentDirectorys.Count += await modelDirectorysRepository.CountAsync(x => x.ParentId == entity.ParentId && !string.IsNullOrWhiteSpace(x.ModelId));
            await modelDirectorysRepository.UpdateAsync(parentDirectorys);
        }

        /// <summary>
        /// 解绑零件
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task UnbindComponent(BindComponentInput input)
        {
            var entity = await modelDirectorysRepository.FirstOrDefaultAsync(x => x.Id == input.DirectoryId);
            if (entity == null) throw new UserFriendlyException("结构不存在，请重新选择");

            if (entity.Type != ModelDirectoryType.零件)
                throw new UserFriendlyException("只能解绑零件，请重新选择");

            if (entity.ModelId.IsNullOrWhiteSpace()) throw new UserFriendlyException("没有可以解绑的零件");

            var modelIdList = ((JArray)JsonConvert.DeserializeObject(entity.ModelId)).Values().ToList();
            modelIdList.Remove(input.ModelId);
            var modelId = JsonConvert.SerializeObject(modelIdList);
            if (modelId == null) modelId = string.Empty;

            entity.ModelId = modelId;
            entity.Count = modelIdList.Count;
            await modelDirectorysRepository.UpdateAsync(entity);

            //更新已绑定零件总数
            var parentDirectorys = await modelDirectorysRepository.FirstOrDefaultAsync(entity.ParentId);
            parentDirectorys.Count += await modelDirectorysRepository.CountAsync(x => x.ParentId == entity.ParentId && !string.IsNullOrWhiteSpace(x.ModelId));
            await modelDirectorysRepository.UpdateAsync(parentDirectorys);
        }

        #endregion
    }
}
